package hu.jonas.allunit.builder;

import hu.jonas.allunit.PluginHelper;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IType;

public class TestFinder implements IResourceVisitor, IResourceDeltaVisitor {

	private Map<IFile, Set<IType>> typesToBuilt = new HashMap<IFile, Set<IType>>();
	private PluginHelper javaCoreHelper; 
	
	public TestFinder() {
		javaCoreHelper = new PluginHelper();
	}
	
	protected TestFinder(PluginHelper javaCoreHelper) {
		this.javaCoreHelper = javaCoreHelper;
	}

	protected void addTypeToBuild(IFile file, IType type) {
		Set<IType> types = typesToBuilt.get(file);
		if (types == null) {
			types = new HashSet<IType>();
			typesToBuilt.put(file, types);
		}
		types.add(type);
	}

	public PluginHelper getJavaCoreHelper() {
		return javaCoreHelper;
	}

	public Set<IType> getTypesToBuilt() {
		Set<IType> result = new HashSet<IType>();
		
		for (Set<IType> types : typesToBuilt.values()) {
			result.addAll(types);
		}
		
		return result;
	}
	
	public void clearTypesToBuilt() {
		typesToBuilt = new HashMap<IFile, Set<IType>>();
	}

	public void setJavaCoreHelper(PluginHelper javaCoreHelper) {
		this.javaCoreHelper = javaCoreHelper;
	}

	@Override
	public boolean visit(IResource resource) throws CoreException {
		
		if (resource instanceof IFile) {
			IType type = getTypeFromFile((IFile) resource);
			
			if (type != null && javaCoreHelper.isTestOrTestSuite(type)) {
				addTypeToBuild((IFile) resource, type);
			}
			
			return false;
		}
		
		if (resource instanceof IContainer) {
			return true;
		}
		
		return false;
	}

	@Override
	public boolean visit(IResourceDelta delta) throws CoreException {
		IResource resource = delta.getResource();

		switch (resource.getType()) {
		case IResource.FILE:
			IFile file = (IFile) resource;
			
			switch (delta.getKind()) {
			case IResourceDelta.ADDED:
			case IResourceDelta.CHANGED:
				IType type = getTypeFromFile(file);
				if (type != null) {
					if (javaCoreHelper.isTestOrTestSuite(type)) {
						addTypeToBuild(file, type);
					} else {
						typesToBuilt.remove(file);
					}
				}
				return false;
				
			case IResourceDelta.REMOVED:
				typesToBuilt.remove(file);
				
				return false;
			}

		case IResource.FOLDER:
		case IResource.PROJECT:
		case IResource.ROOT:
			return true;
		}
		
		return false;
	}
	
	protected IType getTypeFromFile(IFile file) {
		ICompilationUnit compUnit = getCompilationUnit(file);
		if (compUnit != null) {
			return compUnit.findPrimaryType();
		}
		
		return null;
	}

	protected ICompilationUnit getCompilationUnit(IFile file) {
		IJavaElement javaElement = javaCoreHelper.create(file);
		if (javaElement != null &&
				javaElement.getElementType() == IJavaElement.COMPILATION_UNIT) {
			
			if (javaElement instanceof ICompilationUnit) {
				return (ICompilationUnit) javaElement;
			}
		}
		
		return null;
	}
	
}
